﻿namespace SmallGeo;

public static class GeometryExtensions
{
    public static Vector2d ToVector(this LineSegment2d line)
        => Util.ToXY(line);
    public static Vector3d ToVector(this LineSegment3d line)
        => Util.ToXYZ(line);
    public static LineSegment2d ToLineSegment(Vector2d point)
        => Util.ToLineSegment(point);
    public static LineSegment3d ToLineSegment(Vector3d point)
        => Util.ToLineSegment(point);

    #region 四舍五入
    public static Vector2d Round(this Vector2d vector, int digits = 4) => Util.Round(vector, digits);
    public static Vector3d Round(this Vector3d vector, int digits = 4) => Util.Round(vector, digits);
    public static IEnumerable<Vector2d> Round(this IEnumerable<Vector2d> vectors, int digits = 4) => vectors.Select(i => i.Round(digits));
    public static IEnumerable<Vector3d> Round(this IEnumerable<Vector3d> vectors, int digits = 4) => vectors.Select(i => i.Round(digits));
    public static List<Vector2d> Round(this List<Vector2d> vectors, int digits = 4) => vectors.Select(i => i.Round(digits)).ToList();
    public static List<Vector3d> Round(this List<Vector3d> vectors, int digits = 4) => vectors.Select(i => i.Round(digits)).ToList();
    #endregion

    /// <summary>
    /// 长度归一化
    /// </summary>
    public static Vector2d Normalized(this Vector2d vector2d)
        => Util.Normalized(vector2d);

    /// <summary>
    /// 将向量长度置为1
    /// </summary>
    public static Vector3d Normalized(this Vector3d vector3d)
        => Util.Normalized(vector3d);

    /// <summary>
    /// 两点距离
    /// </summary>
    public static double DistanceTo(this Vector2d point, Vector2d pointOther)
        => Util.Length(point - pointOther);

    /// <summary>
    /// 两点距离
    /// </summary>
    public static double DistanceTo(this Vector3d point, Vector3d pointOther)
        => Util.Length(point - pointOther);

    /// <summary>
    /// 弧度转角度,如: 3.141592653589793 => 180°
    /// </summary>
    public static double ToDegree(this double radian)
        => Util.ToDegree(radian);
    /// <summary>
    /// 角度转弧度,如: 180° => 3.141592653589793
    /// </summary>
    public static double ToRadian(this double degree)
        => Util.ToRadian(degree);

    /// <summary>
    /// 两个点是否近似相等, 距离在 tolerance 范围内则认为是相等
    /// </summary>
    public static bool IsNearlySame(this Vector2d point, Vector2d pointOther, double tolerance = 0.0001)
        => Util.IsNearlySame(point, pointOther, tolerance);

    /// <summary>
    /// 两个点是否近似相等, 距离在 tolerance 范围内则认为是相等
    /// </summary>
    public static bool IsNearlySame(this double val1, double val2, double tolerance = 0.0001)
        => Math.Abs((val1 - val2)) < tolerance;

    /// <summary>
    /// 两个点是否近似相等, 距离在 tolerance 范围内则认为是相等
    /// </summary>
    public static bool IsNearlySame(this Vector3d point, Vector3d pointOther, double tolerance = 0.0001)
        => Util.IsNearlySame(point, pointOther, tolerance);

    /// <summary>
    /// 向量长度
    /// </summary>
    public static double Length(this Vector3d vector)
        => Util.Length(vector);

    /// <summary>
    /// 向量长度的平方
    /// </summary>
    public static double LengthSquared(this Vector3d vector)
        => Util.LengthSquared(vector);

    /// <summary>
    /// 线段长度
    /// </summary>
    public static double Length(this LineSegment2d line)
        => Util.Length(line);
    /// <summary>
    /// 线段长度
    /// </summary>
    public static double Length(this LineSegment3d line)
        => Util.Length(line);

    /// <summary>
    /// 计算向量与x轴正方向的夹角,弧度制,逆时针为正,值域: (-PI, PI]
    /// </summary>
    public static double AngleRadian(this Vector2d vector)
        => Util.AngleRadian(vector);

    /// <summary>
    /// 计算向量与 baseVector 方向的夹角,弧度制,逆时针为正,值域: (-PI, PI]
    /// </summary>
    public static double AngleRadian(this Vector2d vector, Vector2d baseVector)
        => Util.AngleRadian(baseVector, vector);

    /// <summary>
    /// 计算两线段表示的直线间的夹角, 值域: [0,PI/2]
    /// </summary>
    public static double AngleRadian(this LineSegment2d line, LineSegment2d line2)
        => Util.AngleRadian(line, line2);

    #region 规范转换角度
    /// <summary>
    /// 将弧度制转为区间: [0,Pi/2] , 就像两条直线的夹角一样
    /// </summary>
    /// <param name="radian"></param>
    /// <returns></returns>
    public static double NormalRadianLikeLine(this double radian)
        => Util.NormalRadianLikeLine(radian);

    /// <summary>
    /// 将弧度制转为区间: (-Pi,Pi] , 就像两条向量的夹角一样
    /// </summary>
    /// <param name="radian"></param>
    /// <returns></returns>
    public static double NormalRadianLikeVector(this double radian)
        => Util.NormalRadianLikeVector(radian);

    /// <summary>
    /// 将弧度制转为区间: [0,Pi] , 就像两条向量的夹角一样(忽略顺逆时针)
    /// </summary>
    /// <param name="radian"></param>
    /// <returns></returns>
    public static double NormalRadianLikeVectorIgnoreClock(this double radian)
        => Util.NormalRadianLikeVectorIgnoreClock(radian);
    #endregion

    #region 旋转、缩放、平移
    #region 2d
    public static Vector2d Rotate(this Vector2d point, double radian)
        => Util.RotateRadian(point, radian);
    public static Vector2d Rotate(this Vector2d point, Vector2d origin, double radian)
        => Util.RotateRadian(point, origin, radian);
    public static Vector2d Translate(this Vector2d point, double x, double y)
        => Util.Translate(point, x, y);
    public static Vector2d Scale(this Vector2d point, double x, double y)
        => Util.Scale(point, x, y);
    public static Vector2d Scale(this Vector2d point, Vector2d origin, double x, double y)
        => Util.Scale(point, origin, x, y);
    #endregion

    #region 3d
    /// <summary>
    /// 将点绕x轴旋转指定度数
    /// </summary>
    public static Vector3d RotateX(this Vector3d point, double radian)
        => Util.RotateX(point, radian);
    /// <summary>
    /// 将点绕经过 throughPoint 的x方向轴旋转指定度数
    /// </summary>
    public static Vector3d RotateX(this Vector3d point, Vector3d throughPoint, double radian)
        => Util.RotateX(point, throughPoint, radian);
    /// <summary>
    /// 将点绕y轴旋转指定度数
    /// </summary>
    public static Vector3d RotateY(this Vector3d point, double radian)
        => Util.RotateY(point, radian);
    /// <summary>
    /// 将点绕经过 throughPoint 的y方向轴旋转指定度数
    /// </summary>
    public static Vector3d RotateY(this Vector3d point, Vector3d throughPoint, double radian)
        => Util.RotateY(point, throughPoint, radian);
    /// <summary>
    /// 将点绕z轴旋转指定度数
    /// </summary>
    public static Vector3d RotateZ(this Vector3d point, double radian)
        => Util.RotateZ(point, radian);
    /// <summary>
    /// 将点绕经过 throughPoint 的z方向轴旋转指定度数
    /// </summary>
    public static Vector3d RotateZ(this Vector3d point, Vector3d throughPoint, double radian)
        => Util.RotateZ(point, throughPoint, radian);

    /// <summary>
    /// 将点绕过原点的指定方向轴旋转
    /// </summary>
    public static Vector3d RotateAxis(this Vector3d point, Vector3d axis, double radian)
        => Util.RotateAxis(point, axis, radian);
    /// <summary>
    /// 将点绕过 throughPoint 的指定方向轴旋转
    /// </summary>
    public static Vector3d RotateAxis(this Vector3d point, Vector3d throughPoint, Vector3d axis, double radian)
        => Util.RotateAxis(point, throughPoint, axis, radian);

    public static Vector3d Translate(this Vector3d point, double x, double y, double z)
        => Util.Translate(point, x, y, z);
    public static Vector3d Scale(this Vector3d point, double x, double y, double z)
        => Util.Scale(point, x, y, z);
    public static Vector3d Scale(this Vector3d point, Vector3d origin, double x, double y, double z)
        => Util.Scale(point, origin, x, y, z);
    #endregion

    #endregion

    #region 点是否在线上
    public static bool IsNearlyOnLineSegment(this Vector2d point, LineSegment2d lineSegment, double tolerance = 0.0001)
        => Util.IsNearlyPointOnLineSegment(point, lineSegment, tolerance);
    public static bool IsNearlyOnLineSegment(this Vector3d point, LineSegment3d lineSegment, double tolerance = 0.0001)
        => Util.IsNearlyPointOnLineSegment(point, lineSegment, tolerance);
    #endregion

    #region 两条线是否平行
    public static bool IsNearlyParallel(this LineSegment2d line, LineSegment2d line2, double degreeTolerance = 1)
        => Util.IsNearlyParallel(line, line2, degreeTolerance);
    #endregion

    #region 两条线是否近似相交
    public static bool IsNearyIntersect(this LineSegment2d line, LineSegment2d line2, double tolerance = 0.0001)
        => Util.IsNearyLineSegmentIntersect(line, line2, tolerance);
    #endregion
}
